package Viewer;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;
import java.util.StringTokenizer;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JWindow;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import DataModel.AminoAcidTable;
import DataModel.Feature;
import DataModel.FeatureBucket;
import DataModel.FeatureHolder;
import DataModel.LociHolder;
import DataModel.Locus;
import DataModel.Sequence;
import DataModel.Tupel;
import Interfaces.Track;
import Parser.ParseEmbl;
import Parser.ParseFastA;
import Parser.ParseFeatureFormat;
import Parser.ParseGenBank;
import Settings.Settings;
import Utils.OrfFinder;

/**
 * The {@link Viewer} represents a GeneScapes session. This class contains all
 * further classes which are needed for a interactive use of GeneScapes
 * 
 * @author Stefan Lorenz<br>
 * <br>
 *         29.11.2012
 */
@SuppressWarnings("serial")
public class Viewer extends JPanel implements Observer {
	/**
	 * The newly annotated "genome" which holds the annotation list with its
	 * {@link Feature}s
	 */
	private LociHolder newGenome;
	/**
	 * Contains Features which are created manually
	 */
	private ArrayList<FeatureBucket> newAnnotationList;
	/**
	 * Represents the current created Feature\n no input at the beginning of
	 * creation
	 */
	private Feature currentCreatedFeature;
	/**
	 * Represents a position tupel for the current created feature
	 */
	private Tupel currentCreatedTupel;
	/**
	 * The number of self annotated features
	 */
	private int novelFeatureCounter;
	/**
	 * Contains all selected features
	 */
	private FeatureHolder selectedFeatureList;
	/**
	 * The track table for loading and handle data
	 */
	private TrackTable trackTable;
	/**
	 * Array of tracks which represent the loaded data
	 */
	private Track[] loadedTracks = new Track[16];
	/**
	 * Hold the mitfs to search for
	 */
	private String[] motif = { "", "", "" };
	/**
	 * Array for track shifting
	 */
	private TrackShifting[] trackPositionLines = new TrackShifting[this.loadedTracks.length];
	/**
	 * Optimized filechooser
	 */
	private FileChooserX fileChooser;
	/**
	 * Holds the position of the single track
	 */
	private int[] positionOfTrack = new int[this.loadedTracks.length];
	/**
	 * The Range of the shown region
	 */
	private int rangeOfBrowser;
	/**
	 * Reference name of chromsome or contig
	 */
	private String selectedChromosome = "NA";
	/**
	 * Panel where to draw
	 */
	private DrawPanel drawPanel;
	/**
	 * Is motif search shown?
	 */
	private boolean showMotif = false;
	/**
	 * Is sequence shown?
	 */
	private boolean showSequence = false;
	/**
	 * Search motif on plus strand
	 */
	private boolean showPlusSearch = true;
	/**
	 * Search motif on minus strand
	 */
	private boolean showMinusSearch = true;
	/**
	 * Popupmenu
	 */
	private PopUpMenu popUpMenu;
	/**
	 * Setting holder
	 */
	private Settings settings;
	/**
	 * The menu of the {@link Viewer}
	 */
	private SettingsMenu settingsFrame;
	/**
	 * Amino acid table
	 */
	private AminoAcidTable aminoAcidTable;
	/**
	 * The panel where search panels are embedded
	 */
	private DownPanel downPanel;
	/**
	 * The Scrollpane of the {@link DownPanel}
	 */
	private JScrollPane drawPanelScrollPane;
	/**
	 * The panel where the {@link DrawPanel} and the {@link DownPanel} are
	 * embedded
	 */
	private JPanel visualizer;
	/**
	 * The memory bar
	 */
	private JProgressBar memoryBar;
	/**
	 * Slider Panel
	 */
	private SliderPanel sliderPanel;
	/**
	 * Is viewer enabled?
	 */
	private boolean isViewerEnabled;
	/**
	 * Shows the status newly annotated features positions -2 if start and stop
	 * is missing<br>
	 * -1 if stop is missing<br>
	 * 0 if both positions are set
	 */
	private int isFeatureUnpositioned;
	/**
	 * Split pane to split frame
	 */
	private JSplitPane splitPane;
	/**
	 * Index of first bucket
	 */
	private int firstBucketIndex = 0;
	/**
	 * Index of selected track
	 */
	private int selectedTrack = 1;
	/**
	 * Frame of the search and shift panel
	 */
	private JFrame searchShift;

	/**
	 * Constructor of the Viewer for statring an GeneScapes session
	 * 
	 * @param file
	 *            first file to visualize
	 */
	public Viewer(File file) {
		System.out.println("Starting browser window: " + file.getName());
		this.isViewerEnabled = true;

		this.aminoAcidTable = new AminoAcidTable(1);
		this.settingsFrame = new SettingsMenu(this);
		this.settingsFrame.setAlwaysOnTop(true);

		// trying to load saved settings
		this.settings = new Settings();
		try {
			this.settings = this.settings.loadSettings(new File("settings.xml"));
			System.out.println("Loading: Standard Settings");
		} catch (Exception e1) {

		}
		if (settings == null)
			this.settings = new Settings();

		for (int i = 0; i < this.positionOfTrack.length; i++) {
			this.positionOfTrack[i] = 0;
			getSettings().getSixFrameSettings()[i].setStartStop(getAminoAcidTable().getStartCodons(), getAminoAcidTable().getStopCodons());
		}
		// load first file into track 1
		ReferenceChooser referenceChooser;
		try {
			referenceChooser = new ReferenceChooser(file);
			if (referenceChooser.isLoadable())
				addTracks(file, 1, referenceChooser.getReference(), referenceChooser.getRange());
		} catch (IOException e) {
			return;
		}

		// add Observer to settings parts
		// maybe needed some time
		// this.settings.addObserver(this);
		// this.settings.getSixFrameSettings().addObserver(this);
		//
		// for (int i = 0; i < settings.getTracksettings().length; i++) {
		// this.settings.getTracksettings()[i].addObserver(this);
		// this.settings.getSequenceSettings(i).addObserver(this);
		// }

		this.settings.getTracksettings()[0].setTrackShown(false);

		this.fileChooser = new FileChooserX();
		this.fileChooser.setFileHidingEnabled(false);
		this.fileChooser.setPreferredSize(new Dimension(600, 600));

		this.newAnnotationList = new ArrayList<FeatureBucket>();

		this.selectedFeatureList = new FeatureHolder();
		this.selectedFeatureList.setTypeOfFile("gff");

		this.selectedChromosome = getName();
		this.setVisible(true);
		this.setLayout(new BorderLayout());
		this.visualizer = new JPanel();
		this.visualizer.setLayout(new BorderLayout(0, 0));
		this.drawPanel = new DrawPanel(this);
		this.drawPanelScrollPane = new JScrollPane(this.drawPanel);
		this.drawPanelScrollPane.setEnabled(false);

		this.setScrollPaneDrawPanelListener();

		this.visualizer.add(drawPanelScrollPane, BorderLayout.CENTER);
		this.drawPanel.setPreferredSize(new Dimension(drawPanel.getWidth(), Toolkit.getDefaultToolkit().getScreenSize().height * 2 - 32));
		this.drawPanelScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		this.sliderPanel = new SliderPanel(this);
		this.sliderPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		this.visualizer.add(sliderPanel, BorderLayout.SOUTH);

		this.drawPanel.setRequestFocusEnabled(true);
		this.drawPanel.setFocusable(true);

		// this.splitPane = new JSplitPane();
		// this.splitPane.setDividerSize(12);
		// this.splitPane.setLeftComponent(visualizer);
		// this.splitPane.setRightComponent(downPanel);
		// this.splitPane.setDividerLocation(Toolkit.getDefaultToolkit().getScreenSize().height);
		// this.splitPane.setOrientation(0);
		// this.splitPane.setResizeWeight(1);

		searchShift = new SearchAndShift();
		searchShift.setAlwaysOnTop(true);

		this.downPanel = new DownPanel(this);
		this.downPanel.setMinimumSize(new Dimension(this.getWidth(), 1));
		this.downPanel.setPreferredSize(new Dimension(this.getWidth(), 200));
		searchShift.add(downPanel);
		searchShift.setPreferredSize(new Dimension(600, 350));
		searchShift.pack();

		this.add(visualizer);

		// this.add(this.visualizer, BorderLayout.CENTER);
		this.rangeOfBrowser = 20000;
		this.drawPanel.setShowSelectionFrame(false);

		// load first track into feature table
		this.downPanel.getFeatureTable().fillTable(1);
		newAnnotatedGenome();
		writeLastLoadedFiles(true);
		updateSliders();
		this.popUpMenu = new PopUpMenu(this);
		this.downPanel.requestFocus();
	}

	/**
	 * Adds Changelistener to drawpanel scrollpane to repaint by action
	 */
	private void setScrollPaneDrawPanelListener() {
		this.drawPanelScrollPane.getViewport().addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {
				Viewer.this.drawPanelScrollPane.repaint();
			}
		});
	}

	/**
	 * Update slider after scrolling or zooming
	 */
	public void updateSliders() {
		setPositionOfBrowser(1, this.positionOfTrack[1]);
		setRangeOfBrowser(this.rangeOfBrowser);
		this.sliderPanel.update();
	}

	/**
	 * Checks if a Str is a number
	 * 
	 * @param str
	 *            string to check
	 * @return true if it is a number false otherwise
	 */
	public boolean isNumber(String str) {
		try {
			Integer.parseInt(str);
			return true;
		} catch (NumberFormatException e) {
			return false;
		}
	}

	/**
	 * Create Cigar String to Sequence
	 * 
	 * @param sequence
	 *            Sequence to parse CIGAR String
	 * @param cigarString
	 * @return
	 */
	public String parseBackCigar(String sequence, String cigarString) {
		StringBuilder compString = new StringBuilder();
		String number = "";
		String cases = "";
		int jumpIndex = 0;
		int oldIndex = 0;
		for (int i = 0; i < cigarString.length(); i++) {
			if (Character.isDigit(cigarString.charAt(i))) {
				number += cigarString.charAt(i);
			} else {
				cases = String.valueOf(cigarString.charAt(i));
				if (cases.equals("I") || cases.equals("M") || cases.equals("X") || cases.equals("=") || cases.equals("S")) {
					jumpIndex += Integer.parseInt(number);
					compString.append(sequence.substring(oldIndex, jumpIndex));
					oldIndex = jumpIndex;
				}
				if (cases.equals("D") || cases.equals("P")) {
					for (int j = 0; j < Integer.parseInt(number); j++) {
						compString.append("*");
					}
				}
				if (cases.equals("N")) {
					for (int j = 0; j < Integer.parseInt(number); j++) {
						compString.append(".");
					}
				}
				number = "";
			}
		}
		return compString.toString();
	}

	/**
	 * Adds 'gene' and 'CDS' to Bucket if they are not already in PRE: Bucket
	 * must contain a 'mRNA' feature to create 'gene' and 'CDS'
	 */
	public void addGeneAndCDS(FeatureBucket tar) {
		boolean isGene = false;
		boolean isMrna = false;
		boolean isCDS = false;
		Feature mrna = null;
		for (int i = 0; i < tar.getFeaturesOfBucket().size(); i++) {
			if (tar.getFeaturesOfBucket().get(i).getType().equals("gene"))
				isGene = true;
			else if (tar.getFeaturesOfBucket().get(i).getType().equals("mRNA")) {
				mrna = tar.getFeaturesOfBucket().get(i);
				isMrna = true;
			} else if (tar.getFeaturesOfBucket().get(i).getType().equals("CDS"))
				isCDS = true;
		}
		if (!isMrna) {
			JOptionPane.showMessageDialog(this, "RNA-feature is needed", "No RNA found!", JOptionPane.INFORMATION_MESSAGE);
			return;
		}
		if (!(this.loadedTracks[1].getTypeOfFile().equals("gbk") || this.loadedTracks[1].getTypeOfFile().equals("embl") || this.loadedTracks[1].getTypeOfFile().equals("fas")))
			JOptionPane.showMessageDialog(this, "Wrong reference track", "No *.embl or *.gbk", JOptionPane.INFORMATION_MESSAGE);
		LociHolder genome = (LociHolder) this.loadedTracks[1];
		// ******* gene ******
		Feature gene = new Feature();
		gene.setAbsoultePositions(new Tupel(mrna.getStart(), mrna.getStop()));
		gene.addTupelToListOfPositions(new Tupel(mrna.getStart(), mrna.getStop()));
		gene.setLocus(genome.getListOfLoci().get(0).getLocusName());
		gene.setName(mrna.getName());
		gene.setScore(0);
		gene.setStrand(mrna.getStrand());
		gene.setType("gene");
		ArrayList<String> addiGene = new ArrayList<String>();
		addiGene.add("/gene=\"" + mrna.getName() + "\"");
		gene.setAdditionalInformation(addiGene);
		gene.setTrackIndex(0);

		// ****** CDS *******
		Feature cds = new Feature();

		OrfFinder orfFinder = new OrfFinder(this.getAminoAcidTable().getTranslTable());

		ArrayList<String> seqs = new ArrayList<String>();
		String mergedSeq = "";
		for (int j = 0; j < mrna.getListOfPositions().size(); j++) {
			mergedSeq += genome.getSequenceFromTo(genome.getListOfLoci().get(0).getLocusName(), mrna.getListOfPositions().get(j).getStart(), mrna.getListOfPositions().get(j).getStop());
			seqs.add(genome.getSequenceFromTo(genome.getListOfLoci().get(0).getLocusName(), mrna.getListOfPositions().get(j).getStart(), mrna.getListOfPositions().get(j).getStop()));
		}
		Tupel t = orfFinder.getCDSPositions(mergedSeq, mrna.getStrand());
		String as = "";
		if (t != null) {
			cds.setLocus(genome.getListOfLoci().get(0).getLocusName());
			cds.setName(mrna.getName());
			cds.setStrand(mrna.getStrand());
			cds.setType("CDS");
			cds.setTrackIndex(0);
			ArrayList<String> addiCDS = new ArrayList<String>();
			addiCDS.add("/gene=\"" + mrna.getName() + "\"");

			for (int j = 0; j < mrna.getAdditionalInformation().size(); j++) {
				if (mrna.getAdditionalInformation().get(j).contains("/product=")) {
					addiCDS.add(mrna.getAdditionalInformation().get(j));
				}
				if (mrna.getAdditionalInformation().get(j).contains("/note=")) {
					addiCDS.add(mrna.getAdditionalInformation().get(j));
				}
				if (mrna.getAdditionalInformation().get(j).contains("/remarks=")) {
					addiCDS.add(mrna.getAdditionalInformation().get(j));
				}
			}
			String ntSeq = orfFinder.getCDSSequence(mergedSeq, mrna.getStrand());
			as = "";

			for (int j = 0; j < ntSeq.length(); j += 3) {
				if (aminoAcidTable.get(ntSeq.substring(j, j + 3)) == null) {
					as += "X";
				} else {
					as += aminoAcidTable.get(ntSeq.substring(j, j + 3));
				}
			}
			addiCDS.add("/protein_id=\"pid_" + mrna.getName() + ".1\"");
			addiCDS.add("/transl_table=" + this.getAminoAcidTable().getTranslTable());
			addiCDS.add("/translation=\"" + as + "\"");

			cds.setAdditionalInformation(addiCDS);

			// ********* Exons Positions of CDS
			Tupel absPos = new Tupel();
			ArrayList<Tupel> tupelList = new ArrayList<Tupel>();

			if (mrna.getStrand().equals("+") && seqs.size() == 1) {
				absPos = new Tupel(mrna.getStart() + t.getStart(), mrna.getStart() + t.getStop() - 1);
				tupelList.add(absPos);
				cds.setListOfPositions(tupelList);
			} else if (mrna.getStrand().equals("-") && seqs.size() == 1) {
				absPos = new Tupel(mrna.getStop() - t.getStop() + 1, mrna.getStop() - t.getStart());
				tupelList.add(absPos);
				cds.setListOfPositions(tupelList);
			} else {
				int intronLength = 0;
				// PLUS
				if (mrna.getStrand().equals("+")) {
					for (int j = 0; j < mrna.getListOfPositions().size(); j++) {

						if (j > 0) {
							intronLength += mrna.getListOfPositions().get(j).getStart() - mrna.getListOfPositions().get(j - 1).getStop();
						}
						// start & stop position liegt in exon
						if (mrna.getStart() + t.getStart() + intronLength >= mrna.getListOfPositions().get(j).getStart() && mrna.getStart() + t.getStart() + intronLength <= mrna.getListOfPositions().get(j).getStop()
								&& mrna.getStart() + t.getStop() + intronLength >= mrna.getListOfPositions().get(j).getStart() && mrna.getStart() + t.getStop() + intronLength <= mrna.getListOfPositions().get(j).getStop()) {

							tupelList.add(new Tupel(mrna.getStart() + t.getStart() + intronLength - j, mrna.getStart() + t.getStop() + intronLength - j - 1));
						}
						// start in & end aussen
						if (mrna.getStart() + t.getStart() + intronLength >= mrna.getListOfPositions().get(j).getStart() && mrna.getStart() + t.getStart() + intronLength <= mrna.getListOfPositions().get(j).getStop()
								&& mrna.getStart() + t.getStop() + intronLength >= mrna.getListOfPositions().get(j).getStop()) {

							tupelList.add(new Tupel(mrna.getStart() + t.getStart() + intronLength - j, mrna.getListOfPositions().get(j).getStop()));
							// System.out.println(start + " " + stop);
						}
						// start aussen ende aussen
						if (mrna.getStart() + t.getStart() + intronLength < mrna.getListOfPositions().get(j).getStart() && mrna.getStart() + t.getStop() + intronLength > mrna.getListOfPositions().get(j).getStop()) {

							tupelList.add(new Tupel(mrna.getListOfPositions().get(j).getStart(), mrna.getListOfPositions().get(j).getStop()));
							// System.out.println(start + " " + stop);
						}
						// start aussen ende in
						if (mrna.getStart() + t.getStart() + intronLength < mrna.getListOfPositions().get(j).getStart() && mrna.getStart() + t.getStop() + intronLength > mrna.getListOfPositions().get(j).getStart()
								&& mrna.getStart() + t.getStop() + intronLength < mrna.getListOfPositions().get(j).getStop()) {

							tupelList.add(new Tupel(mrna.getListOfPositions().get(j).getStart(), mrna.getStart() + t.getStop() + intronLength - j - 1));
							// System.out.println(start + " " + stop);
						}
					}
				}
				// MINUS
				if (mrna.getStrand().equals("-")) {

					for (int j = mrna.getListOfPositions().size(); j >= 1; j--) {
						if (j < mrna.getListOfPositions().size()) {
							intronLength += mrna.getListOfPositions().get(j).getStart() - mrna.getListOfPositions().get(j - 1).getStop();
						}
						int size = mrna.getListOfPositions().size() - j;
						// start & stop position liegt in exon
						if (mrna.getStop() - t.getStart() - intronLength >= mrna.getListOfPositions().get(j - 1).getStart() && mrna.getStop() - t.getStart() - intronLength <= mrna.getListOfPositions().get(j - 1).getStop()
								&& mrna.getStop() - t.getStop() - intronLength >= mrna.getListOfPositions().get(j - 1).getStart() && mrna.getStop() - t.getStop() - intronLength <= mrna.getListOfPositions().get(j - 1).getStop()) {

							tupelList.add(new Tupel(mrna.getStop() - t.getStop() - intronLength + size + 1, mrna.getStop() - t.getStart() - intronLength + size));
							// System.out.println("fall1");
						}
						// start in & end aussen
						if (mrna.getStop() - t.getStart() - intronLength >= mrna.getListOfPositions().get(j - 1).getStart() && mrna.getStop() - t.getStart() - intronLength <= mrna.getListOfPositions().get(j - 1).getStop()
								&& mrna.getStop() - t.getStop() - intronLength < mrna.getListOfPositions().get(j - 1).getStart()) {

							tupelList.add(new Tupel(mrna.getListOfPositions().get(j - 1).getStart(), mrna.getStop() - t.getStart() - intronLength + size));
							// System.out.println("fall2");
						}
						// start aussen ende aussen
						if (mrna.getStop() - t.getStart() - intronLength > mrna.getListOfPositions().get(j - 1).getStop() && mrna.getStop() - t.getStop() - intronLength < mrna.getListOfPositions().get(j - 1).getStart()) {

							tupelList.add(new Tupel(mrna.getListOfPositions().get(j - 1).getStart(), mrna.getListOfPositions().get(j - 1).getStop()));
							// System.out.println("fall3");
						}
						// start aussen ende in
						if (mrna.getStop() - t.getStart() - intronLength > mrna.getListOfPositions().get(j - 1).getStop() && mrna.getStop() - t.getStop() - intronLength >= mrna.getListOfPositions().get(j - 1).getStart()
								&& mrna.getStop() - t.getStop() - intronLength <= mrna.getListOfPositions().get(j - 1).getStop()) {

							tupelList.add(new Tupel(mrna.getStop() - t.getStop() - intronLength + size + 1, mrna.getListOfPositions().get(j - 1).getStop()));
							// System.out.println("fall4");
						}
					}
					ArrayList<Tupel> sortedList = new ArrayList<Tupel>();
					for (int j = tupelList.size() - 1; j >= 0; j--) {
						sortedList.add(tupelList.get(j));
					}
					tupelList = sortedList;
				}
				cds.setListOfPositions(tupelList);
				cds.setAbsoultePositions(new Tupel(cds.getListOfPositions().get(0).getStart(), cds.getListOfPositions().get(cds.getListOfPositions().size() - 1).getStop()));
			}

		}
		if (!isGene)
			tar.getFeaturesOfBucket().add(0, gene);
		if (!isCDS) {
			try {
				cds.setAbsoultePositions(new Tupel(cds.getListOfPositions().get(0).getStart(), cds.getListOfPositions().get(cds.getListOfPositions().size() - 1).getStop()));
				tar.getFeaturesOfBucket().add(cds);
			} catch (IndexOutOfBoundsException e) {
				e.fillInStackTrace();
			}
		}
	}

	/**
	 * Creates an reg expression from a IUPAC entered sequence
	 * 
	 * @param sequence
	 *            sequence for motif search
	 * @return the regular expression for motif search
	 */
	public String getRegularExpressionIUPAC(String sequence) {
		if (sequence.equals(""))
			return "";

		sequence = sequence.toUpperCase();

		String regExp = "(";

		for (int i = 0; i < sequence.length(); i++) {
			if (sequence.charAt(i) == 'R') {
				regExp += "(A|G)";
			} else if (sequence.charAt(i) == 'Y') {
				regExp += "(C|T)";
			} else if (sequence.charAt(i) == 'S') {
				regExp += "(G|C)";
			} else if (sequence.charAt(i) == 'W') {
				regExp += "(A|T)";
			} else if (sequence.charAt(i) == 'K') {
				regExp += "(G|T)";
			} else if (sequence.charAt(i) == 'M') {
				regExp += "(A|C)";
			} else if (sequence.charAt(i) == 'B') {
				regExp += "(C|G|T)";
			} else if (sequence.charAt(i) == 'D') {
				regExp += "(A|G|T)";
			} else if (sequence.charAt(i) == 'H') {
				regExp += "(A|C|T)";
			} else if (sequence.charAt(i) == 'V') {
				regExp += "(A|C|G)";
			} else if (sequence.charAt(i) == 'N') {
				regExp += "(A|G|T|C)";
			} else if (sequence.charAt(i) == 'A') {
				regExp += "A";
			} else if (sequence.charAt(i) == 'G') {
				regExp += "G";
			} else if (sequence.charAt(i) == 'T') {
				regExp += "T";
			} else if (sequence.charAt(i) == 'C') {
				regExp += "C";
			} else {
				System.err.println("No IUPAC code entered!!");
			}
		}
		regExp += ")";
		return regExp;
	}

	/**
	 * Returns the complement of a nucleotide.
	 * 
	 * @param base
	 *            to get complement to
	 * @return the complement base
	 */
	public char getComplementOfBase(char base) {
		if (base == 'A')
			return 'T';
		else if (base == 'T')
			return 'A';
		else if (base == 'C')
			return 'G';
		else if (base == 'G')
			return 'C';
		return base;
	}

	/**
	 * Adds a new feature to the ABC list
	 */
	public void addNewNovelFeature(String strand, int index, int positioned) {
		int count = this.getNovelFeatureCounter();
		this.createNewBucketWithEmptyFeature();
		this.getCurrentCreatedFeature().setName("nTAR#" + count);
		this.getCurrentCreatedFeature().setStrand(strand);
		this.getCurrentCreatedFeature().getAdditionalInformation().add("/gene=\"nTAR#" + count + "\"");
		this.getCurrentCreatedFeature().getAdditionalInformation().add("/transcript_id=\"nTAR#" + count + "\".1");
		this.getCurrentCreatedFeature().setType("mRNA");
		this.getCurrentCreatedFeature().setTrackIndex(index);
		this.setFeatureUnpositioned(positioned);
	}

	/**
	 * Searches for Orthologues in all tracks for selected feature PRE: Must
	 * have orhtologue tag like: /note="C.dub orthologue: CD36_51380"
	 */
	public void findOrthologueInTrack() {
		if (this.selectedFeatureList.size() > 0) {
			String ortho = null;
			for (int i = 0; i < this.selectedFeatureList.get(0).getAdditionalInformation().size(); i++) {
				if (this.selectedFeatureList.get(0).getAdditionalInformation().get(i).contains("/note=") && this.selectedFeatureList.get(0).getAdditionalInformation().get(i).contains("orthologue")) {
					ortho = this.selectedFeatureList.get(0).getAdditionalInformation().get(i).split("orthologue: ")[1];
					ortho = ortho.replace("\"", "");
					System.out.println(ortho);
				} else if (this.selectedFeatureList.get(0).getAdditionalInformation().get(i).contains("/orthologue=")) {
					ortho = this.selectedFeatureList.get(0).getAdditionalInformation().get(i).split("=")[1];
					ortho = ortho.replace("\"", "");
					System.out.println(ortho);
				}
			}
			if (ortho != null) {
				for (int i = 0; i < this.loadedTracks.length; i++) {
					if (this.loadedTracks[i] == null)
						continue;

					if (this.loadedTracks[i].getTypeOfFile().equals("embl") || this.loadedTracks[i].getTypeOfFile().equals("gbk")) {

						LociHolder genome = ((LociHolder) this.loadedTracks[i]);
						int index = genome.getBucketByName(ortho);
						if (index != -1) {
							int diff = this.selectedFeatureList.get(0).getStart() - this.positionOfTrack[this.selectedFeatureList.get(0).getTrackIndex()];

							this.positionOfTrack[i] = genome.getListOfLoci().get(0).getBucketList().get(index).getStart() - diff;
							for (int j = 0; j < this.trackPositionLines.length; j++) {
								if (j == i)
									continue;
								if (this.trackPositionLines[j].getAnchor() == i)
									this.positionOfTrack[j] = genome.getListOfLoci().get(0).getBucketList().get(index).getStart() - diff;
							}
							this.drawPanel.repaint();
						}
					} else if (this.loadedTracks[i].getTypeOfFile().equals("gtf")) {

						FeatureHolder rff = ((FeatureHolder) this.loadedTracks[i]);
						int index = rff.getFeatureIndexByName(ortho);
						System.out.println("ortho found index" + index);
						if (index != -1) {
							int diff = this.selectedFeatureList.get(0).getStart() - this.positionOfTrack[this.selectedFeatureList.get(0).getTrackIndex()];

							this.positionOfTrack[i] = rff.get(index).getStart() - diff;
							for (int j = 0; j < this.trackPositionLines.length; j++) {
								if (j == i)
									continue;
								if (this.trackPositionLines[j].getAnchor() == i)
									this.positionOfTrack[j] = rff.get(index).getStart() - diff;
							}
							this.drawPanel.repaint();
						}
					}
				}
			}

		}
	}

	/**
	 * Adds a new data file to the {@link Viewer#trackTable}.<br>
	 * If file does not exist the functions prints a terminal info and returns<br>
	 * It depends on the file format which type of visualization gets enabled
	 * and which not.<br>
	 * This method also writes the actual loaded files into a new file
	 * {@link Viewer#writeLastLoadedFiles(boolean)}.
	 * 
	 * @param file
	 *            to load in track
	 * @param index
	 *            of track to load into
	 * @throws IOException
	 */
	public void addTracks(File file, int index, String reference, String range) throws IOException {
		// returns if file does not exist
		if (!file.exists()) {
			System.out.println("File does not exist: " + file.getName());
			return;
		}

		System.out.println("Loading: " + file.getName());
		// get extension of file and add it to track
		String extension = file.getName().substring(file.getName().lastIndexOf(".")).toUpperCase();
		// GFF BED WIG GTF SAM and BEDGRAPH format
		if (extension.contains(".GFF") || extension.equals(".BED") || extension.equals(".WIG") || extension.equals(".BEDGRAPH") || extension.equals(".GTF") || extension.equals(".SAM") || extension.equals(".BAM") || extension.equals(".BB")
				|| extension.equals(".BW")) {
			this.loadedTracks[index] = (Track) new ParseFeatureFormat(file, reference, range).getList();

			// if loaded file of track has no features...
			if (this.loadedTracks[index].getElementsOfTrack() == 0) {
				this.loadedTracks[index] = null;
				return;
			}
			this.settings.getSequenceSettings(index).setShown(false);
			this.settings.getTracksettings()[index].setReadWiggleShown(true);
			this.settings.getTracksettings()[index].setTrackShown(true);
			this.loadedTracks[index].setTrackIndexToFeatures(index);
		}
		// GENBANK format
		else if (extension.equals(".GBK") || extension.equals(".GB")) {
			extension = "GBK";

			if (index > 0)
				this.loadedTracks[index] = (Track) new ParseGenBank(file, reference, range).getLociHolder();
			else {
				this.newGenome = new ParseGenBank(file, reference, range).getLociHolder();
				this.loadedTracks[index] = this.newGenome;
				this.newAnnotationList = newGenome.getListOfLoci().get(0).getBucketList();
			}
			this.settings.getSequenceSettings(index).setShown(true);
			this.settings.getTracksettings()[index].setReadWiggleShown(false);
			this.settings.getTracksettings()[index].setTrackShown(true);
			this.loadedTracks[index].setTrackIndexToFeatures(index);

		}
		// EMBL format
		else if (extension.contains(".EMBL")) {

			if (index > 0)
				this.loadedTracks[index] = (Track) new ParseEmbl(file, reference, range).getLociHolder();
			else {
				this.newGenome = new ParseEmbl(file, reference, range).getLociHolder();
				this.loadedTracks[index] = this.newGenome;
				this.newAnnotationList = newGenome.getListOfLoci().get(0).getBucketList();
			}
			this.settings.getSequenceSettings(index).setShown(true);
			this.settings.getTracksettings()[index].setReadWiggleShown(false);
			this.settings.getTracksettings()[index].setTrackShown(true);
			this.loadedTracks[index].setTrackIndexToFeatures(index);

		}
		// FASTA format
		else if (extension.equals(".FAS") | extension.equals(".FA") | extension.contains(".FASTA")) {

			this.loadedTracks[index] = (Track) new ParseFastA(file, reference, range).getLociHolder();
			if (index == 0)
				this.newAnnotationList = newGenome.getListOfLoci().get(0).getBucketList();

			this.settings.getSequenceSettings(index).setShown(true);
			this.settings.getTracksettings()[index].setReadWiggleShown(false);
			this.settings.getTracksettings()[index].setTrackShown(false);
			this.loadedTracks[index].setTrackIndexToFeatures(index);

		}
		// write changes into file
		writeLastLoadedFiles(true);
	}

	/**
	 * Adds a file to the first empty track in track table
	 * 
	 * @param file
	 */
	// public void addToNextEmptyTrack(File file) {
	// for (int i = 2; i < this.loadedTracks.length; i++) {
	// if (this.loadedTracks[i] == null)
	// try {
	// addTracks(file, i);
	// break;
	// } catch (IOException e) {
	// System.err.println("Can not load " + file.getName());
	// }
	// }
	// }

	/**
	 * Resets the track position all to that of the reference data (track1)
	 */
	public void resetTrackPositions() {
		for (int i = 0; i < this.getPositionOfTrack().length; i++) {
			if (i != 1) {
				this.getPositionOfTrack()[i] = this.getPositionOfTrack()[1];
			}
		}
		this.drawPanel.repaint();
	}

	/**
	 * Returns max size of tracks
	 * 
	 * @return the size of the loaded data
	 */
	public int getSizeOfReference() {
		int max = 0;
		try {
			for (int i = 0; i < this.loadedTracks.length; i++) {
				if (loadedTracks[1].getSize() > max)
					max = loadedTracks[1].getSize();
			}
		}
		// if track is empty
		catch (NullPointerException e) {
		}
		return max;
	}

	/**
	 * Returns the drawpenel
	 * 
	 * @return the drawpanel
	 */
	public DrawPanel getDrawPanel() {
		return drawPanel;
	}

	/**
	 * Sets the drawpanel
	 * 
	 * @param drawPanel
	 *            the drawpanel
	 */
	public void setDrawPanel(DrawPanel drawPanel) {
		this.drawPanel = drawPanel;
	}

	/**
	 * Sets selected locus
	 * 
	 * @param locus
	 *            selected locus
	 */
	public void setSelectedLocus(String locus) {
		this.selectedChromosome = locus;

	}

	/**
	 * Returns arrayList with loaded Tracks
	 * 
	 * @return array with all tracks
	 */
	public Track[] getLoadedTracks() {
		return this.loadedTracks;
	}

	/**
	 * Returns the amino acid table
	 * 
	 * @return the amino acid table
	 */
	public AminoAcidTable getAminoAcidTable() {
		return this.aminoAcidTable;
	}

	public String getSelectedLocus() {
		return selectedChromosome;
	}

	/**
	 * Returns a list with all marked features
	 * 
	 * @return list with marked features
	 */
	public FeatureHolder getSelectedFeatureList() {
		return this.selectedFeatureList;
	}

	/**
	 * Sets a list with selected features
	 * 
	 * @param l
	 *            a list with features
	 */
	public void setSelectedFeatureList(FeatureHolder l) {
		this.selectedFeatureList = l;
	}

	/**
	 * Returns the optimized filechooser
	 * 
	 * @return the fileChooser
	 */
	public FileChooserX getFileChooser() {
		this.fileChooser.setFileFilter(null);
		return fileChooser;
	}

	/**
	 * Is sequence shown?
	 * 
	 * @return Is sequence shown?
	 */
	public boolean isSequenceShown() {
		return this.showSequence;
	}

	/**
	 * Sets the sequence visible or not
	 * 
	 * @param bool
	 */
	public void setSequenceShown(boolean bool) {
		this.showSequence = bool;
		this.drawPanel.repaint();
	}

	/**
	 * Sets the settings for visualisation
	 * 
	 * @param settings
	 *            the settings to set
	 */
	public void setSettings(Settings settings) {
		if (settings != null) {
			this.settings = settings;
			this.drawPanel.repaint();
		}
	}

	/**
	 * Returns the settings
	 * 
	 * @return the settings
	 */
	public Settings getSettings() {
		return settings;
	}

	/**
	 * Creates a new bucket with empty feature for editing and creating<br>
	 * Positions, Type etc must be defined
	 */
	public void createNewBucketWithEmptyFeature() {
		this.settings.getTracksettings()[0].setTrackShown(true);
		Feature f = new Feature();
		f.setType("mRNA");
		f.setStrand("+");
		this.currentCreatedFeature = f;
		this.newAnnotationList.add(new FeatureBucket(f));
		createCurrentCreatedTupel();
	}

	/**
	 * Removes the last created bucket wich is marked
	 */
	public void removeLastBucket() {
		if (this.newAnnotationList.size() > 0)
			this.newAnnotationList.remove(newAnnotationList.size() - 1);
	}

	/**
	 * Creates an tupel for the current annotated features
	 */
	public void createCurrentCreatedTupel() {
		this.currentCreatedTupel = new Tupel(1, 1);
	}

	/**
	 * Adds a tupel to the newly current annotated feature
	 */
	public void addTupelToCurrentCreatedFeature() {
		int newlastAnno = this.newAnnotationList.size() - 1;
		this.newAnnotationList.get(newlastAnno).getFeaturesOfBucket().get(this.newAnnotationList.get(newlastAnno).getFeaturesOfBucket().size() - 1).addTupelToListOfPositions(new Tupel(currentCreatedTupel.getStart(), currentCreatedTupel.getStop()));
		this.newAnnotationList.get(newlastAnno).refreshBucketPositions();
	}

	/**
	 * Sets the positions to the tupel
	 * 
	 * @param pos
	 *            position to set tu tupel
	 * @throws NullPointerException
	 */
	public void setPositionToActualCreatedTupel(int pos) throws NullPointerException {
		if (currentCreatedTupel.getStart() == 1 & currentCreatedTupel.getStop() == 1) {
			this.currentCreatedTupel.setStart(pos);
			isFeatureUnpositioned = -1;
		} else if (currentCreatedTupel.getStart() != 1 & currentCreatedTupel.getStop() == 1 && pos < currentCreatedTupel.getStart()) {
			JOptionPane.showMessageDialog(this, "Stop position must be greater than start position!", "WARNING", JOptionPane.WARNING_MESSAGE);
		} else if (currentCreatedTupel.getStart() != 1 & currentCreatedTupel.getStop() == 1) {
			this.currentCreatedTupel.setStop(pos);
			addTupelToCurrentCreatedFeature();
			isFeatureUnpositioned = 0;
		} else if (currentCreatedTupel.getStart() != 1 & currentCreatedTupel.getStop() != 1) {
			createCurrentCreatedTupel();
			setPositionToActualCreatedTupel(pos);
		}
	}

	/**
	 * creates an new annotation every new annotated information gets lost
	 */
	public void newAnnotatedGenome() {

		this.novelFeatureCounter = 0;
		this.newGenome = new LociHolder();
		this.newGenome.setFile(new File("export.gbk"));
		this.newGenome.setTypeOfFile("gbk");

		this.newAnnotationList = new ArrayList<FeatureBucket>();
		this.currentCreatedFeature = null;
		this.currentCreatedTupel = null;
		Locus locus = new Locus();
		locus.setTypeOfSequence("DNA");
		locus.setFeatureBucket(this.newAnnotationList);
		ArrayList<Locus> lociList = new ArrayList<Locus>();
		lociList.add(locus);
		this.newGenome.setListOfLoci(lociList);
		this.newGenome.setFile(new File(this.loadedTracks[1].getFile().getAbsolutePath().substring(0, this.loadedTracks[1].getFile().getAbsolutePath().lastIndexOf(".")) + ".gbk"));
		this.loadedTracks[0] = (Track) this.newGenome;
		this.settings.getTracksettings()[0].setReadWiggleShown(false);
		this.settings.getSequenceSettings(0).setShown(false);
		this.settings.getTracksettings()[0].setTrackShown(false);
	}

	/**
	 * Searches in all feature buckets for described feature and removes it if
	 * bucket is empty bucket also gets removed
	 * 
	 * @param selectedFeature
	 *            selected feature
	 */
	public void removeAnnotatedFeature(Feature selectedFeature) {
		int index = getBucketIndexOfFeature(selectedFeature);
		if (index != -1) {
			this.newAnnotationList.get(index).getFeaturesOfBucket().remove(selectedFeature);
			if (this.newAnnotationList.get(index).getFeaturesOfBucket().size() == 0)
				this.newAnnotationList.remove(index);
		}
	}

	/**
	 * Creates an empty feature to the bucket of selected Feature.<br>
	 * Start and stop positions and type have to get set<br>
	 * Default: + stranded
	 * 
	 * @param selectedFeature
	 *            selected feature
	 */
	public void addEmptyFeatureToBucketOf(Feature selectedFeature) {
		int index = getBucketIndexOfFeature(selectedFeature);
		if (index != -1) {
			Feature f = new Feature();
			f.setStrand("+");
			currentCreatedFeature = f;
			createCurrentCreatedTupel();
			this.newAnnotationList.get(index).getFeaturesOfBucket().add(f);
		}
	}

	/**
	 * Writes to "lastOpened.txt" all files which are loaded you can use this
	 * file to load all these data at the next program start
	 */
	public void writeLastLoadedFiles(boolean isAutomatic) {
		try {
			File file = new File("lastOpened.gss");
			if (!isAutomatic) {
				if (this.getFileChooser().showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
					file = this.getFileChooser().getSelectedFile();
				}
			}
			if (!file.getName().endsWith(".gss"))
				file = new File(file.getAbsolutePath() + ".gss");
			BufferedWriter bw = new BufferedWriter(new FileWriter(file));
			bw.write(this.getPositionOfBrowser(1) + "\t" + this.getRangeOfBrowser());
			bw.newLine();
			for (int i = 1; i < this.loadedTracks.length; i++) {
				try {
					bw.write(i + "\t" + this.loadedTracks[i].getFile().getAbsolutePath());
					bw.newLine();
				} catch (NullPointerException e) {
				}
			}
			bw.flush();
			bw.close();
		} catch (IOException e) {
			System.err.println("can not save last openend files...");
		}

	}

	/**
	 * Checks a path and return a file...allows whitespaces in path
	 * 
	 * @param substring
	 *            path of file
	 * @return the file of the path
	 */
	public File checkPath(String substring) {
		StringTokenizer st = new StringTokenizer(substring);
		String string = st.nextToken().toString();
		while (st.hasMoreElements()) {
			string += " " + st.nextToken().toString();
		}
		return new File(string);
	}

	/**
	 * Updates the memory bar
	 */
	public void updateMemoryBarValues() {
		try {
			this.memoryBar.setValue((int) ((float) (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1000000));
		} catch (NullPointerException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Returns the index of the bucket of the 'selectedFeature'.<br>
	 * If not found -1.
	 * 
	 * @param selectedFeature
	 *            selected feature
	 * @return the index of the bucket which contains the feature or -1
	 */
	public int getBucketIndexOfFeature(Feature selectedFeature) {
		for (int i = 0; i < this.newAnnotationList.size(); i++) {
			if (this.newAnnotationList.get(i).getFeaturesOfBucket().contains(selectedFeature))
				return i;
		}
		return -1;
	}

	/**
	 * Sets the feature which is the current one and can get edited
	 * 
	 * @param actualCreatedFeature
	 */
	public void setCurrentCreatedFeature(Feature actualCreatedFeature) {
		this.currentCreatedFeature = actualCreatedFeature;
	}

	/**
	 * Removes the Bucket of the given feature
	 * 
	 * @param selectedFeature
	 *            selected feature
	 */
	public void removeBucket(Feature selectedFeature) {
		if (getBucketIndexOfFeature(selectedFeature) != -1)
			this.newAnnotationList.remove(getBucketIndexOfFeature(selectedFeature));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
	 * 
	 * Not neede yet
	 */
	public void update(Observable o, Object arg) {

		if (o.getClass().toString().contains("SixFrameSettings")) {

		} else if (o.getClass().toString().contains("TrackSettings")) {

		} else if (o.getClass().toString().contains("SequenceSettings")) {

		} else if (o.getClass().toString().contains("Settings")) {

		}
	}

	/**
	 * Enables / disables the Viewer
	 * 
	 * @param isEnabled
	 */
	public void setEnabledViewer(boolean isEnabled) {
		this.isViewerEnabled = isEnabled;
		if (isEnabled) {
			this.drawPanel.setShowToolTips(true);
			this.drawPanel.addMouseWheelListener(this.drawPanel);
			this.drawPanel.addMouseListener(this.drawPanel);
			this.drawPanel.addKeyListener(this.drawPanel);
			this.sliderPanel.addMouseListener(this.sliderPanel);
			setEnableSlider(true);
		} else {
			this.drawPanel.setShowToolTips(false);
			this.drawPanel.removeMouseWheelListener(this.getDrawPanel().getMouseWheelListeners()[0]);
			this.drawPanel.removeMouseListener(this.drawPanel.getMouseListeners()[0]);
			this.drawPanel.removeKeyListener(this.drawPanel.getKeyListeners()[0]);
			this.sliderPanel.removeMouseListener(this.sliderPanel.getMouseListeners()[0]);

			setEnableSlider(false);
		}
		this.drawPanel.repaint();
	}

	/**
	 * Returns if the viewer is enabled or not
	 * 
	 * @return status of viewer
	 */
	public boolean isEnabledViewer() {
		return this.isViewerEnabled;
	}

	public void openFullScreenMode() {
		this.getSettings().setFullScreen(true);
		final JFrame win = new JFrame();
		win.setLocation(0, 0);

		win.setPreferredSize(Toolkit.getDefaultToolkit().getScreenSize());
		win.setUndecorated(true);

		win.add(this.visualizer, BorderLayout.CENTER);

		win.addMouseWheelListener(new MouseWheelListener() {
			public void mouseWheelMoved(MouseWheelEvent e) {
				getDrawPanel().repaint();
			}
		});

		AbstractAction act = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {
				getDrawPanel().repaint();
			}
		};
		AbstractAction esc = new AbstractAction() {
			public void actionPerformed(ActionEvent e) {
				add(visualizer);
				win.dispose();
				revalidate();
				getSettings().setFullScreen(false);
			}
		};
		win.getRootPane().getActionMap().put("repaint", act);
		win.getRootPane().getActionMap().put("esc", esc);
		InputMap im = win.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_A, 0), "repaint");
		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, 0), "repaint");
		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, 0), "repaint");
		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_D, 0), "repaint");
		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "esc");

		win.setFocusable(true);
		win.setVisible(true);
		win.pack();
	}

	// ******************************************************************
	// SIMPLE GETTER AND SETTER
	// ******************************************************************
	/**
	 * @param on
	 */
	public void setShowRestrictionSite(boolean on) {
		this.showMotif = on;
		this.drawPanel.repaint();
	}

	/**
	 * @return is moptif search shown?
	 */
	public boolean getShowRestrictionSite() {
		return this.showMotif;
	}

	/**
	 * @param restrictionSite
	 *            the restrictionSite to set index of searchfield
	 */
	public void setMotif(String restrictionSite, int index) {
		this.motif[index] = restrictionSite;
		this.drawPanel.repaint();
	}

	/**
	 * @return restriction site of the field index
	 */
	public String getMotif(int index) {
		return this.motif[index];
	}

	/**
	 * @param fileChooser
	 *            the fileChooser to set
	 */
	public void setFileChooser(FileChooserX fileChooser) {
		this.fileChooser = fileChooser;
	}

	/**
	 * @return the position tupel of the current annotated feature
	 */
	public Tupel getCurrentCreatedTupel() {
		return this.currentCreatedTupel;
	}

	/**
	 * @return the current annotating feature
	 */
	public Feature getCurrentCreatedFeature() {
		return this.currentCreatedFeature;
	}

	/**
	 * @param newAnnotationList
	 */
	public void setNewAnnotationList(ArrayList<FeatureBucket> newAnnotationList) {
		this.newAnnotationList = newAnnotationList;
	}

	/**
	 * @return list with manual created annotations
	 */
	public ArrayList<FeatureBucket> getNewAnnotationList() {
		return newAnnotationList;
	}

	/**
	 * @return the sliderPanel
	 */
	public SliderPanel getSliderPanel() {
		return sliderPanel;
	}

	/**
	 * @param newGenome
	 */
	public void setNewGenome(LociHolder newGenome) {
		this.newGenome = newGenome;
	}

	/**
	 * @return the "genome" of the new annotated features
	 */
	public LociHolder getNewGenome() {
		return newGenome;
	}

	/**
	 * Returns the increased number of novel feature
	 * 
	 * @return the counter for novel features
	 */
	public int getNovelFeatureCounter() {
		this.novelFeatureCounter++;
		return this.novelFeatureCounter;
	}

	/**
	 * @param showPlusSearch
	 */
	public void setShowPlusSearch(boolean showPlusSearch) {
		this.showPlusSearch = showPlusSearch;
	}

	/**
	 * @return is plus motif search shown
	 */
	public boolean isShowPlusSearch() {
		return showPlusSearch;
	}

	/**
	 * @param showMinusSearch
	 */
	public void setShowMinusSearch(boolean showMinusSearch) {
		this.showMinusSearch = showMinusSearch;
	}

	/**
	 * @return is minus motif search shown
	 */
	public boolean isShowMinusSearch() {
		return showMinusSearch;
	}

	/**
	 * @return the downpanel
	 */
	public DownPanel getDownPanel() {
		return downPanel;
	}

	/**
	 * @param newAnnotationGenome
	 */
	public void setNewAnnotationGenome(LociHolder newAnnotationGenome) {
		this.newGenome = newAnnotationGenome;
	}

	/**
	 * @return the new annotated "genome"
	 */
	public LociHolder getNewAnnotationGenome() {
		return this.newGenome;
	}

	/**
	 * @param bool
	 */
	public void setEnableSlider(boolean bool) {
		this.sliderPanel.setEnabled(bool);
	}

	/**
	 * @return the track table
	 */
	public TrackTable getTrackTable() {
		return trackTable;
	}

	/**
	 * @param trackTable
	 */
	public void setTrackTable(TrackTable trackTable) {
		this.trackTable = trackTable;
	}

	/**
	 * Opens the Track Menu window
	 * 
	 * @param selectedMenu
	 * @param choosenItem
	 */
	public void openSettings(Tupel selectedMenu, int choosenItem) {
		this.settingsFrame.openSettings(selectedMenu, choosenItem);
	}

	/**
	 * @return the positionInGenome
	 */
	public int[] getPositionOfTrack() {
		return positionOfTrack;
	}

	/**
	 * @param trackPositionLines
	 *            the trackPositionLines to set
	 */
	public void setTrackPositionLines(int index, TrackShifting trackPositionLines) {
		this.trackPositionLines[index] = trackPositionLines;
	}

	/**
	 * @return the trackPositionLines
	 */
	public TrackShifting getTrackPositionLines(int index) {
		return trackPositionLines[index];
	}

	/**
	 * Sets the range of the browser
	 * 
	 * @param x
	 *            size of range
	 */
	public void setRangeOfBrowser(int x) {
		if (x >= 10) {
			this.rangeOfBrowser = x;
			sliderPanel.update();
		}
	}

	/**
	 * Sets the position of the track
	 * 
	 * @param index
	 *            index of track
	 * @param x
	 *            position of the track
	 */
	public void setPositionOfBrowser(int index, int x) {
		this.positionOfTrack[index] = x;
		this.trackPositionLines[index].refreshTrackPositionLine(x);
		this.sliderPanel.update();
	}

	/**
	 * Returns the position of the track with index
	 * 
	 * @param index
	 *            index of track
	 * @return position of the track
	 */
	public int getPositionOfBrowser(int index) {
		return this.positionOfTrack[index];
	}

	/**
	 * Returns the seen range of the browser
	 * 
	 * @return the range of the browser
	 */
	public int getRangeOfBrowser() {
		return this.rangeOfBrowser;
	}

	/**
	 * @param isFeatureUnpositioned
	 *            the isFeatureUnpositioned to set
	 */
	public void setFeatureUnpositioned(int isFeatureUnpositioned) {
		this.isFeatureUnpositioned = isFeatureUnpositioned;
	}

	/**
	 * @return the isFeatureUnpositioned
	 */
	public int isFeatureUnpositioned() {
		return isFeatureUnpositioned;
	}

	/**
	 * @param index
	 */
	public void setFirstBucketIndex(int index) {
		this.firstBucketIndex = index;
	}

	/**
	 * @return the index of the first bucket
	 */
	public int getFirstBucketIndex() {
		return this.firstBucketIndex;
	}

	/**
	 * @param selectedTrack
	 */
	public void setSelectedTrack(int selectedTrack) {
		this.selectedTrack = selectedTrack;
	}

	/**
	 * @return selected track
	 */
	public int getSelectedTrack() {
		return selectedTrack;
	}

	/**
	 * @param drawPanelScrollPane
	 */
	public void setDrawPanelScrollPane(JScrollPane drawPanelScrollPane) {
		this.drawPanelScrollPane = drawPanelScrollPane;
	}

	/**
	 * @return the scrollpane of the drawpanel
	 */
	public JScrollPane getDrawPanelScrollPane() {
		return drawPanelScrollPane;
	}

	/**
	 * @param visualizer
	 */
	public void setVisualizer(JPanel visualizer) {
		this.visualizer = visualizer;
	}

	/**
	 * @return the vizualizer panel
	 */
	public JPanel getVisualizer() {
		return visualizer;
	}

	/**
	 * @param memoryBar
	 */
	public void setMemoryBar(JProgressBar memoryBar) {
		this.memoryBar = memoryBar;
	}

	/**
	 * @param splitPane
	 *            the splitPane to set
	 */
	public void setSplitPane(JSplitPane splitPane) {
		this.splitPane = splitPane;
	}

	/**
	 * @return the splitPane
	 */
	public JSplitPane getSplitPane() {
		return splitPane;
	}

	/**
	 * @param aminoAcidTable
	 *            the aminoAcidTable to set
	 */
	public void setAminoAcidTable(AminoAcidTable aminoAcidTable) {
		this.aminoAcidTable = aminoAcidTable;
	}

	/**
	 * Returns the sequences of the selected features
	 * 
	 * @return the sequences of selected features
	 */
	public ArrayList<Sequence> getSelectedSequences() {
		ArrayList<Sequence> list = new ArrayList<>();

		for (int i = 0; i < this.getSelectedFeatureList().size(); i++) {
			Feature l = this.getSelectedFeatureList().get(i);

			ArrayList<String> seq;
			if (this.getLoadedTracks()[this.getTrackPositionLines(l.getTrackIndex()).getAnchor()].getTypeOfFile().equals("gbk") || this.getLoadedTracks()[this.getTrackPositionLines(l.getTrackIndex()).getAnchor()].getTypeOfFile().equals("fasta")
					|| this.getLoadedTracks()[this.getTrackPositionLines(l.getTrackIndex()).getAnchor()].getTypeOfFile().equals("fas") || this.getLoadedTracks()[this.getTrackPositionLines(l.getTrackIndex()).getAnchor()].getTypeOfFile().equals("fa")
					|| this.getLoadedTracks()[this.getTrackPositionLines(l.getTrackIndex()).getAnchor()].getTypeOfFile().equals("embl")) {

				seq = ((LociHolder) this.getLoadedTracks()[this.getTrackPositionLines(l.getTrackIndex()).getAnchor()]).getSplicedSequenceFromTo(((LociHolder) this.getLoadedTracks()[this.getTrackPositionLines(l.getTrackIndex()).getAnchor()])
						.getListOfLoci().get(0).getLocusName(), l.getListOfPositions());
				String sequence = "";
				for (int j = 0; j < seq.size(); j++) {
					sequence += seq.get(j);
				}
				list.add(new Sequence("nucl", l.getName(), sequence));
			} else {
				System.err.println("No Sequence in track " + l.getTrackIndex() + " for " + l.getName() + " " + l.getStart() + ".." + l.getStop());
				continue;
			}
			if (seq.get(0) == null) {
				System.err.println("No Sequence in track " + l.getTrackIndex() + " for " + l.getName() + " " + l.getStart() + ".." + l.getStop());
				continue;
			}
		}
		return list;
	}

	public boolean isSearchShiftVisible() {
		return searchShift.isVisible();
	}

	public void setSearchShiftVisible(boolean visible) {
		this.searchShift.setLocation((int) this.getLocationOnScreen().getX(), (int) (this.getLocationOnScreen().getY() + this.drawPanel.getVisibleRect().getHeight() - this.searchShift.getHeight()));
		this.searchShift.setVisible(visible);
		this.drawPanel.requestFocus();
	}

	public void closeAll() {
		try{
			this.searchShift.dispose();
			this.trackTable.dispose();
		}
		catch(Exception e){e.printStackTrace();}
	}

	public PopUpMenu getPopUpMenu() {
		return popUpMenu;
	}
}
